package com.coincalf.service.impl;

import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.coincalf.dto.*;
import com.coincalf.entity.Market;
import com.coincalf.entity.TurnoverOrder;
import com.coincalf.entity.TurnoverRecord;
import com.coincalf.framework.enums.AdminUserType;
import com.coincalf.framework.enums.BusinessType;
import com.coincalf.framework.enums.OrderStatus;
import com.coincalf.framework.enums.OrderType;
import com.coincalf.mapper.TurnoverOrderMapper;
import com.coincalf.service.*;
import com.coincalf.user.dto.UserDTO;
import com.coincalf.user.feign.UserServiceClient;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * <p>
 * 成交订单 服务实现类
 * </p>
 *
 * @author qiang
 * @since 2018-05-12
 */
@Service
@Slf4j
public class TurnoverOrderServiceImpl extends ServiceImpl<TurnoverOrderMapper, TurnoverOrder> implements TurnoverOrderService {

    @Autowired
    private TurnoverRecordService turnoverRecordService;
    @Autowired
    private EntrustOrderService entrustOrderService;
    @Autowired
    private MarketService marketService;
    @Autowired
    private UserServiceClient userServiceClient;
    @Autowired
    private AccountService accountService;


    /**
     * 获取并保存成交数据
     *
     * @param marketId 交易对ID
     * @return
     */
    @Override
    public TurnoverDataDTO queryAndSaveTurnoverData(long marketId) {
        TurnoverDataDTO turnoverData = baseMapper.queryTurnoverData(marketId);
        if (turnoverData.getPrice().compareTo(BigDecimal.ZERO) > 0) {
            TurnoverRecord turnoverRecord = new TurnoverRecord();
            turnoverRecord.setMarketId(marketId)
                    .setPrice(turnoverData.getPrice())
                    .setVolume(turnoverData.getVolume());
            turnoverRecordService.insert(turnoverRecord);
        }
        return turnoverData;
    }

    /**
     * 获取最新成交价
     *
     * @param marketId 交易对ID
     * @return
     */
    @Override
    public BigDecimal queryCurrentPrice(Long marketId) {
        BigDecimal price = baseMapper.queryCurrentPrice(marketId);
        if (price == null) {
            // 如果没有成交价则获取交易对配置的开盘价
            Market market = marketService.getMarketById(marketId);
            return market.getOpenPrice();
        }
        return price;
    }

    /**
     * 获取24小时成交数据
     *
     * @param marketId 交易对ID
     * @return
     */
    @Override
    public TurnoverData24HDTO query24HDealData(long marketId) {
        return baseMapper.query24HDealData(marketId);
    }

    @Override
    public LoadingCache<Long, List<TradeDealOrderDTO>> DEAL_ORDER_CACHE_INSTANCE() {
        return DEAL_ORDER_CACHE;
    }

    /**
     * 币币交易最新成交记录缓存实例
     */
    private LoadingCache<Long, List<TradeDealOrderDTO>> DEAL_ORDER_CACHE = CacheBuilder.newBuilder()
            .build(new CacheLoader<Long, List<TradeDealOrderDTO>>() {
                @Override
                public List<TradeDealOrderDTO> load(Long marketId) {
                    return initDealOrders(marketId);
                }
            });

    /**
     * 查询最新成交记录
     *
     * @param marketId
     * @return
     */
    private List<TradeDealOrderDTO> initDealOrders(Long marketId) {
        return baseMapper.selectDealOrders(marketId);
    }

    /**
     * 订单管理-成交记录
     *
     * @param page   分页参数
     * @param userId 用户ID
     * @param symbol 交易对标识符
     * @param type   买卖类型
     * @return
     */
    @Override
    public Page<DealRecordDTO> selectOrders(Page<DealRecordDTO> page, long userId, String symbol, int type) {
        int start = (page.getCurrent() - 1) * page.getSize();
        page.setTotal(baseMapper.selectOrdersCount(userId, symbol, type));
        return page.setRecords(baseMapper.selectOrders(userId, symbol, type, start, page.getSize()));
    }

    /**
     * 创新交易，今日成交
     *
     * @param userId 用户ID
     * @return
     */
    @Override
    public List<ForexTodayTurnoverDTO> selectTodayList(Long userId) {
        return baseMapper.selectTodayList(userId);
    }

    /**
     * 撮合成功后扣减资金
     *
     * @param txDTO
     */
    @Override
    @Transactional
    public void match(TxDTO txDTO) {
        // 成交数量
        BigDecimal volume = txDTO.getVol();
        // 成交价
        BigDecimal price = txDTO.getPrice();
        // 成交金额 = 成交量 * 成交价
        BigDecimal amount = volume.multiply(price).setScale(8, BigDecimal.ROUND_HALF_UP);
        // 买入手续费 = 成交金额 * 买入手续费比例
        BigDecimal buyFee = amount.multiply(txDTO.getBuyFeeRate()).setScale(8, BigDecimal.ROUND_HALF_UP);
        // 卖出手续费 = 成交金额 * 交易市场配置的卖出手续费率
        BigDecimal sellerFee = amount.multiply(txDTO.getSellFeeRate()).setScale(8, BigDecimal.ROUND_HALF_UP);
        // 成交订单
        TurnoverOrder turnoverOrder = TxDTOMapper.INSTANCE.from(txDTO);
        if (txDTO.getTradeType() == 1) {
            turnoverOrder.setOrderId(txDTO.getBuyOrderId());    // 成交订单号
        } else {
            turnoverOrder.setOrderId(txDTO.getSellOrderId());   // 成交订单号
        }
        turnoverOrder
                .setDealBuyFee(buyFee)                          // 成交买单手续费
                .setDealBuyFeeRate(txDTO.getBuyFeeRate())       // 成交买单手续费率
                .setDealSellFee(sellerFee)                      // 成交卖单手续费
                .setDealSellFeeRate(txDTO.getSellFeeRate())     // 成交卖单手续费率
                .setVolume(volume)                              // 成交数量
                .setPrice(price)                                // 成交价格
                .setAmount(amount)                              // 成交金额
                .setStatus(OrderStatus.DEAL.getCode());         // 成交状态
        // 创建成交单记录
        baseMapper.insert(turnoverOrder);
        entrustOrderService.modifyEntrustOrder(txDTO.getBuyOrderId(), volume, OrderType.BUY);
        entrustOrderService.modifyEntrustOrder(txDTO.getSellOrderId(), volume, OrderType.SELL);
        // 管理员用户
        UserDTO adminUser = userServiceClient.queryAdminUser(AdminUserType.ADMIN.getUserName());

        // 更新买单用户账户余额
        accountService.transferAmount(txDTO.getBuyUserId(),     // 买单用户ID
                txDTO.getSellUserId(),                          // 卖单用户ID
                txDTO.getBuyCoinId(),                           // 买单支付币种
                amount,                                         // 买单成交金额
                BusinessType.TRADE_DEAL,                        // 业务类型：币币交易撮合成交
                turnoverOrder.getId());                         // 成交订单ID
        // 更新卖单用户账户余额
        accountService.transferAmount(txDTO.getSellUserId(),    // 卖单用户ID
                txDTO.getBuyUserId(),                           // 买单用户ID
                txDTO.getSellCoinId(),                          // 卖单支付币种
                volume,                                         // 卖单成交数量
                BusinessType.TRADE_DEAL,                        // 业务类型：币币交易撮合成交
                turnoverOrder.getId());                         // 成交订单ID
        // 收取买单手续费
        accountService.transferAmount(txDTO.getBuyUserId(),     // 买单用户ID
                adminUser.getId(),                              // 管理员用户ID
                txDTO.getBuyCoinId(),                           // 买单支付币种
                buyFee,                                         // 买单成交手续费
                BusinessType.TRADE_DEAL_FEE,                    // 业务类型：币币交易撮合成交手续费
                turnoverOrder.getId());                         // 成交订单ID
        // 收取卖单手续费
        accountService.transferAmount(txDTO.getSellUserId(),    // 卖单用户ID
                adminUser.getId(),                              // 管理员用户ID
                txDTO.getBuyCoinId(),                           // 买单支付币种
                sellerFee,                                      // 卖单成交手续费
                BusinessType.TRADE_DEAL_FEE,                    // 业务类型：币币交易撮合成交手续费
                turnoverOrder.getId());                         // 成交订单ID
    }
}
